

namespace apeng {



	export class Maths {

		public static readonly PI = Math.PI

		public static readonly _d2r = Maths.PI / 180.0

		public static readonly _r2d = 180.0 / Maths.PI

		/**
		 * 两个数是否在范围内
		 * @param value1 
		 * @param value2 
		 * @param range 
		 */
		public static isRange(value1: number, value2: number, range: number): boolean {
			return Math.abs(value1 - value2) <= range
		}


		/**
		 * 判断一个数是否为偶数
		 * @param {number} value
		 * @returns {boolean}
		 */
		public static isEven(value: number): boolean {
			return value % 2 == 0
		}

		/**
		 * 把角度换算成弧度
		 * @param a 
		 */
		public static toRadian(a: number): number {
			return a * Maths._d2r
		}

		/**
		 * 取value的小数部分
		 * @param value 
		 */
		public static decimal(value: number): number {
			value = value - (Math.floor(value))
			return value
		}

		/**
		 * 把弧度换算成角度。
		 * @param a 
		 */
		public static toDegree(a: number, is_ormalize: boolean = true): number {
			if (a == undefined)
				return 0
			if (is_ormalize)
				a = this.normalizeAngle(a)
			return a * Maths._r2d
		}

		/**归一化弧度 */
		public static normalizeAngle(angle: number) {
			angle = angle % (2 * Maths.PI)
			if (angle < 0) {
				angle += (2 * Maths.PI)
			}
			return angle
		}

		/**
		 * 两个数字之间的线性插值，比率设置其偏向每一端的程度
		 * a + (b - a) * r
		 * @method lerp
		 * @param {Number} a number A
		 * @param {Number} b number B
		 * @param {Number} r ratio between 0 and 1
		 * @param {Number} fuzzyEquals 校验ab范围 如达到了 返回null
		 * @return {Number}
		 * @example
		 * var a = Maths.lerp(0, 1, .2); // .2
		 * var b = Maths.lerp(1, 2, .5); // 1.5
		 * var b = Maths.lerp(1, 2, .2); // 1.2
		 */
		public static lerp(a: number, b: number, r: number): number {
			return a + (b - a) * r
		}

		/**
		 * 限定浮点数的取值范围为 0 ~ 1 之间
		 * @method clamp01
		 * @param {Number} value
		 * @return {Number}
		 * @example
		 * var v1 = Maths.clamp01(20);  // 1;
		 * var v2 = Maths.clamp01(-1);  // 0;
		 * var v3 = Maths.clamp01(0.5); // 0.5;
		 */
		public static clamp01(value: number): number {
			return value < 0 ? 0 : value < 1 ? value : 1
		}

		/**
		 * 限定浮点数的最大最小值
		 * 数值大于 max 则返回 max
		 * 数值小于 min 则返回 min
		 * 否则返回自身
		 * @method clampf
		 * @param {Number} value
		 * @param {Number} min
		 * @param {Number} max
		 * @return {Number}
		 * @example
		 * var v1 = Maths.clampf(20, 0, 20); // 20;
		 * var v2 = Maths.clampf(-1, 0, 20); //  0;
		 * var v3 = Maths.clampf(10, 0, 20); // 10;
		 */
		public static clampf(value: number, min: number, max: number): number {
			if (min > max) {
				var temp = min
				min = max
				max = temp
			}
			return value < min ? min : value < max ? value : max
		}

		/**
		 * true  在范围内
		 * @param value 
		 * @param min 
		 * @param max 
		 */
		public static isClampf(value: number, min: number, max: number): boolean {
			if (min > max) {
				var temp = min
				min = max
				max = temp
			}
			if (value <= max && value >= min)
				return true
			else
				return false
		}


		/**
		 * 随机值与`value`比较
		 * 数值 0 ～ value 返回true
		 * 数值 1 ～ value 返回false
		 * @param {number} value
		 * @returns {boolean}
		 * @example 
		 * var a = Maths.isRandom(0.5);
		 */
		public static isRandom(value: number, random?: number): boolean {
			if (!value)
				return false
			if (value >= 1)
				return true
			if (value <= 0)
				return false
			if (!random)
				random = Math.random()
			return value > random
		}

		/**
		 * @param min 
		 * @param max 
		 * @param is_int 默认转换为整型
		 * @returns 返回 min - max 的值， 包括 min max
		 */
		public static minToMax(min: number, max: number, isInt: boolean = true, random?: number): number {
			if (min == max) return min
			if (!random)
				random = Math.random()
			if (min < 0) {
				if (isInt)
					return Math.round(random * (Math.abs(min) + max)) + min
				else
					return random * (Math.abs(min) + max) + min
			}
			if (isInt)
				return Math.round(random * (max - min)) + min
			else
				return random * (max - min) + min
		}

		/**
		 * 返回 0 到 max
		 * @param max 
		 * @returns {0 ~ max} 不包括 max
		 * @example
		 * var a = Maths.zeroToMax(10); // 3
		 * var b = Maths.zeroToMax(1); // 0
		 */
		public static zeroToMax(max: number, random?: number): number {
			if (max <= 1)
				return 0
			if (!random)
				random = Math.random()
			return Math.floor((random == 1 ? 0.5 : random) * max)
		}

		public static toFixed(value: number, count: number): number {
			let mul = Math.pow(10, count)
			return Math.floor(value * mul) / mul
		}

		public static arrAdd(value: number[]): number {
			let count = 0
			for (let num of value)
				count += num
			return count
		}


		/**
		 * 找到num在arr所在的区间
		 * @param arr 
		 * @param num 
		 * @param num 
		 * @param isContainNum 是否= 
		 */
		public static findNumSection(
			arr: number[],
			num: number,
			out?: { i: number, count: number },
			isContainNum: boolean = false
		) {
			if (!out)
				out = { i: 0, count: 0 }

			out.i = arr.length
			out.count = 0
			for (let i = 0; i < arr.length; i++) {
				out.count += arr[i]
				if (isContainNum) {
					if (num <= out.count) {
						out.i = i
						return out
					}
				}
				else
					if (num < out.count) {
						out.i = i
						return out
					}
			}
			return out
		}

		/**
		 * 权重随机
		 * @param arr 
		 * @returns 数组索引 
		 */
		public static widgetRandom(arr: number[]): number {
			let rand = this.arrAdd(arr) * Math.random()
			let last = 0
			for (let i = 0; i < arr.length; i++) {
				let value = arr[i]
				if (rand >= last && rand < last + value)
					return i
				last += value
			}
			return arr.length - 1
		}

		public static keep2Decimal(val: number) {
			return (Math.floor(val * 100)) / 100
		}


	}
}